package com.vipboot.platform.system.listener;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.vipboot.framework.core.constant.Const;
import com.vipboot.framework.core.util.MapStructUtil;
import com.vipboot.framework.core.util.ObjectUtil;
import com.vipboot.framework.core.util.ServletUtil;
import com.vipboot.framework.core.util.ip.IpAddressUtil;
import com.vipboot.framework.log.event.LogLoginEvent;
import com.vipboot.framework.log.event.LogOperateEvent;
import com.vipboot.framework.satoken.helper.LoginHelper;
import com.vipboot.platform.system.crud.service.monitor.SysLoginLogService;
import com.vipboot.platform.system.crud.service.monitor.SysOperateLogService;
import com.vipboot.platform.system.crud.service.rbac.SysClientService;
import com.vipboot.platform.system.domain.bo.SysLoginLogBo;
import com.vipboot.platform.system.domain.bo.SysOperateLogBo;
import com.vipboot.platform.system.domain.vo.SysClientVo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Slf4j
@Component
public class LogEventListener {

    private final SysClientService sysClientService;
    private final SysLoginLogService sysLoginLogService;
    private final SysOperateLogService sysOperateLogService;

    /**
     * 操作日志记录
     *
     * @param logOperateEvent 操作日志事件
     */
    @Async
    @EventListener
    public void onLogOperateEvent(LogOperateEvent logOperateEvent) {

        SysOperateLogBo operateLog = MapStructUtil.convert(logOperateEvent, SysOperateLogBo.class);
        // 远程查询操作地点
        operateLog.setOperLocation(IpAddressUtil.getRealAddressByIP(operateLog.getOperIp()));
        sysOperateLogService.save(operateLog);
    }

    /**
     * 记录登录信息
     *
     * @param logLoginEvent 登录事件
     */
    @Async
    @EventListener
    public void onLogLoginEvent(LogLoginEvent logLoginEvent) {
        log.info("LogLoginEvent: {}", logLoginEvent);
        HttpServletRequest request = logLoginEvent.getRequest();
        final UserAgent userAgent = UserAgentUtil.parse(ServletUtil.getUserAgent(request));
        final String ip = ServletUtil.getClientIP(request);
        // 客户端信息
        String clientId = request.getHeader(LoginHelper.ClientIdKey);
        SysClientVo client = null;
        if (StringUtils.isNotBlank(clientId)) {
            client = sysClientService.getByClientId(clientId);
        }

        String address = IpAddressUtil.getRealAddressByIP(ip);
        StringBuilder sb = new StringBuilder();
        sb.append(getBlock(ip));
        sb.append(address);
        sb.append(getBlock(logLoginEvent.getUsername()));
        sb.append(getBlock(logLoginEvent.getStatus()));
        sb.append(getBlock(logLoginEvent.getMessage()));
        // 打印信息到日志
        log.info(sb.toString(), logLoginEvent.getArgs());
        // 获取客户端操作系统
        String os = userAgent.getOs().getName();
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        // 封装对象
        SysLoginLogBo logLoginBo = new SysLoginLogBo();
        logLoginBo.setTenantId(logLoginEvent.getTenantId());
        logLoginBo.setUserName(logLoginEvent.getUsername());
        if (ObjectUtil.isNotNull(client)) {
            logLoginBo.setClientKey(client.getClientKey());
            logLoginBo.setDeviceType(client.getDeviceType());
        }
        logLoginBo.setIp(ip);
        logLoginBo.setIpLocation(address);
        logLoginBo.setBrowser(browser);
        logLoginBo.setOs(os);
        logLoginBo.setMsg(logLoginEvent.getMessage());
        // 日志状态
        if (StringUtils.equalsAny(logLoginEvent.getStatus(), Const.LoginSuccess, Const.Logout, Const.Register)) {
            logLoginBo.setStatus(Const.Success);
        } else if (Const.LoginFail.equals(logLoginEvent.getStatus())) {
            logLoginBo.setStatus(Const.Fail);
        }

        // 插入数据
        sysLoginLogService.save(logLoginBo);
    }

    private String getBlock(Object msg) {
        if (msg == null) {
            msg = "";
        }
        return "[" + msg.toString() + "]";
    }
}
